// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Description: Set real kallsyms data
 * Author: Huawei OS Kernel Lab
 * Create: Tue Apr 17 02:24:01 2023
 */
#include <linux/stop_machine.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/set_memory.h>
#include "extract_kallsyms.h"

extern char __start_kallsyms[], __end_kallsyms[];
extern unsigned int kallsyms_num_syms __weak;
extern int *kallsyms_offsets __weak;
extern u8 *kallsyms_names __weak;
extern char *kallsyms_token_table __weak;
extern u16 *kallsyms_token_index __weak;
extern unsigned int *kallsyms_markers __weak;

static int update_kallsyms_buf(void *data)
{
	int ret;
	struct extract_kallsyms_struct *symbuf = data;
	unsigned long start_relro = (unsigned long)__start_kallsyms;
	unsigned long end_relro = (unsigned long)__end_kallsyms;
	unsigned int size = PAGE_ALIGN(end_relro - start_relro);

	if (symbuf == NULL)
		return -EFAULT;

	ret = set_memory_rw(start_relro,  size >> PAGE_SHIFT);
	if (ret)
		return ret;

	kallsyms_names = symbuf->names;
	kallsyms_token_table = symbuf->token_table;
	kallsyms_token_index = symbuf->token_index;
	kallsyms_markers = symbuf->markers;
	kallsyms_num_syms = *(symbuf->num_syms);
	kallsyms_offsets = symbuf->offsets;

	ret = set_memory_ro(start_relro, size >> PAGE_SHIFT);
	if (ret) {
		pr_warn("set kallsyms_section to ro failed\n");
		return ret;
	}

	return 0;
}

int extract_kallsyms_init(struct extract_kallsyms_struct *symbuf)
{
	return stop_machine(update_kallsyms_buf, symbuf, NULL);
}
EXPORT_SYMBOL_NS(extract_kallsyms_init, LIBLINUX_EXTRACT_KALLSYMS);
